/* Microsoft Reference Implementation for TPM 2.0
 *
 *  The copyright in this software is being made available under the BSD License,
 *  included below. This software may be subject to other third party and
 *  contributor rights, including patent rights, and no such rights are granted
 *  under this license.
 *
 *  Copyright (c) Microsoft Corporation
 *
 *  All rights reserved.
 *
 *  BSD License
 *
 *  Redistribution and use in source and binary forms, with or without modification,
 *  are permitted provided that the following conditions are met:
 *
 *  Redistributions of source code must retain the above copyright notice, this list
 *  of conditions and the following disclaimer.
 *
 *  Redistributions in binary form must reproduce the above copyright notice, this
 *  list of conditions and the following disclaimer in the documentation and/or
 *  other materials provided with the distribution.
 *
 *  THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS ""AS IS""
 *  AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
 *  IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE
 *  DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE LIABLE FOR
 *  ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES
 *  (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES;
 *  LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON
 *  ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
 *  (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS
 *  SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
 */
#include "Tpm.h"

/*
记录日志条目的方法是将完整的日志条目输入到TPM内部，而不是在TPM外部执行摘要。 TPM支持的每种散列算法都可能被用于对日志条目执行散列。
 不超过1024个字节的事件可以使用TPM2_PCR_Event()。 超过1024字节的事件可以使用序列命令：TPM2_HashSequenceStart()， 
 TPM2_SequenceUpdate()，和TPM2_EventSequenceComplete()。

TPM2_PCR_Event()和TPM2_EventSequenceComplete()返回一个带标签的摘要列表。 摘要是使用每种实现的散列算法的事件数据摘要。

例：对于实现两种算法(如SHA256和SM3)的TPM，事件命令返回两个带标签的摘要列表。

TPM2_EventSequenceComplete()要求提供适当的授权(见17.7)。

事件的记录也可能是_TPM_Hash_Start/_TPM_Hash_Data/ _TPM_Hash_End序列(H-CRTM事件序列)的结果。 H-CRTM序列的指示来自TPM接口，
而不是通过命令缓冲区。 在接收到_TPM_Hash_Start时，TPM将创建一个事件序列上下文。 如果在TPM接收_TPM_Hash_Start时没有可用的对象
上下文空间，TPM将刷新上下文(供应商的选择)以创建事件序列上下文。 _TPM_Hash_Data用于更新H-CRTM事件序列上下文，_TPM_Hash_End完成该序列。 
H-CRTM事件序列期间计算的摘要或摘要将被扩展到相关平台特异性规范指定的PCR中。 特定于平台的规范可能允许在TPM2_Startup()之前或之后使用
H-CRTM事件序列。 TPM2_Startup()之前的H-CRTM事件会影响PCR[0]。 在TPM2_Startup()之后，一个H-CRTM事件影响PCR[17]。

————————————————
版权声明：本文为CSDN博主「狂奔的乌龟」的原创文章，遵循CC 4.0 BY-SA版权协议，转载请附上原文出处链接及本声明。
原文链接：https://blog.csdn.net/xy010902100449/article/details/127466441


This indication from the TPM interface indicates the start of an H-CRTM measurement sequence. On receipt of this indication, 
the TPM will initialize an H-CRTM Event Sequence context.
If no object memory is available for creation of the sequence context, the TPM will flush the context of an object so that 
creation of the sequence context will always succeed.
A platform-specific specification may allow this indication before TPM2_Startup().
NOTE If this indication occurs after TPM2_Startup(), it is the responsibility of software to ensure that an object context 
slot is available or to deal with the consequences of having the TPM sel ect an arbitrary object to be flushed. If this indication
 occurs before TPM2_Startup() then all context slots are available.

来自 TPM 接口的这个指示指示 H-CRTM 测量序列的开始。 收到此指示后，TPM 将初始化 H-CRTM 事件序列上下文。
如果没有对象内存可用于创建序列上下文，TPM 将刷新对象的上下文，以便序列上下文的创建始终成功。
特定于平台的规范可能允许在 TPM2_Startup() 之前进行此指示。
注意 如果此指示出现在 TPM2_Startup() 之后，则软件有责任确保对象上下文槽可用或处理让 TPM 选择要刷新的任意对象的后果。 如果此指示出现在 
TPM2_Startup() 之前，则所有上下文槽都可用。

*/
// This function is called to process a _TPM_Hash_Start indication.
LIB_EXPORT void
_TPM_Hash_Start(
    void
    )
{
    TPM_RC              result;
    TPMI_DH_OBJECT      handle;

    // 新建一个 hash 对象，并且将其初始化
    // If a DRTM sequence object exists, free it up
    if(g_DRTMHandle != TPM_RH_UNASSIGNED)
    {
        FlushObject(g_DRTMHandle);
        g_DRTMHandle = TPM_RH_UNASSIGNED;
    }

    // Create an event sequence object and store the handle in global
    // g_DRTMHandle. A TPM_RC_OBJECT_MEMORY error may be returned at this point
    // The NULL value for the first parameter will cause the sequence structure to
    // be allocated without being set as present. This keeps the sequence from
    // being left behind if the sequence is terminated early.
    result = ObjectCreateEventSequence(NULL, &g_DRTMHandle);

    // If a free slot was not available, then free up a slot.
    if(result != TPM_RC_SUCCESS)
    {
        // An implementation does not need to have a fixed relationship between
        // slot numbers and handle numbers. To handle the general case, scan for
        // a handle that is assigned and free it for the DRTM sequence.
        // In the reference implementation, the relationship between handles and
        // slots is fixed. So, if the call to ObjectCreateEvenSequence()
        // failed indicating that all slots are occupied, then the first handle we
        // are going to check (TRANSIENT_FIRST) will be occupied. It will be freed
        // so that it can be assigned for use as the DRTM sequence object.
        for(handle = TRANSIENT_FIRST; handle < TRANSIENT_LAST; handle++)
        {
            // try to flush the first object
            if(IsObjectPresent(handle))
                break;
        }
        // If the first call to find a slot fails but none of the slots is occupied
        // then there's a big problem
        pAssert(handle < TRANSIENT_LAST);

        // Free the slot
        FlushObject(handle);

        // Try to create an event sequence object again.  This time, we must
        // succeed.
        result = ObjectCreateEventSequence(NULL, &g_DRTMHandle);
        if(result != TPM_RC_SUCCESS)
            FAIL(FATAL_ERROR_INTERNAL);
    }

    return;
}